package Renderer;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.HashMap;
import javax.media.opengl.GL2;
import Command.LDrawColorT;
import LDraw.Support.ColorLibrary;
import LDraw.Support.GLMatrixMath;
public class LDrawShaderRenderer implements ILDrawRenderer, ILDrawCollector {
public static final int COLOR_STACK_DEPTH = 64;
public static final int TEXTURE_STACK_DEPTH = 128;
public static final int TRANSFORM_STACK_DEPTH = 64;
public static final int DL_STACK_DEPTH = 64;
public boolean useWireFrame = false;
public boolean drawTransparent = false;
/**
* @uml.property name="session"
* @uml.associationEnd
*/
LDrawDLSession session = null; // DL session - this accumulates draw calls
// and
// sorts them.
/**
* @uml.property name="color_now" multiplicity="(0 -1)" dimension="1"
*/
float color_now[]; // Color stack.
/**
* @uml.property name="compl_now" multiplicity="(0 -1)" dimension="1"
*/
float compl_now[];
/**
* @uml.property name="color_stack" multiplicity="(0 -1)" dimension="1"
*/
float color_stack[];
/**
* @uml.property name="color_stack_top"
*/
int color_stack_top = 0;
/**
* @uml.property name="wire_frame_count"
*/
private boolean isWireFrame = false; // wire frame stack is just a count.
/**
* @uml.property name="tex_stack"
* @uml.associationEnd multiplicity="(0 -1)"
*/
LDrawTextureSpec tex_stack[]; // Texture stack from push/pop texture.
/**
* @uml.property name="texture_stack_top"
*/
int texture_stack_top;
/**
* @uml.property name="tex_now"
* @uml.associationEnd
*/
LDrawTextureSpec tex_now;
/**
* @uml.property name="transform_stack" multiplicity="(0 -1)" dimension="1"
*/
float transform_stack[]; // Transform stack from push/pop matrix.
/**
* @uml.property name="transform_stack_top"
*/
int transform_stack_top;
/**
* @uml.property name="transform_now" multiplicity="(0 -1)" dimension="1"
*/
float transform_now[];
/**
* @uml.property name="cull_now" multiplicity="(0 -1)" dimension="1"
*/
float cull_now[];
/**
* @uml.property name="dl_stack"
* @uml.associationEnd multiplicity="(0 -1)"
*/
LDrawDLBuilder dl_stack[]; // DL stack from begin/end DL builds.
/**
* @uml.property name="dl_stack_top"
*/
int dl_stack_top;
/**
* @uml.property name="dl_now"
* @uml.associationEnd
*/
LDrawDLBuilder dl_now; // This is the DL being built "right now".
/**
* @uml.property name="mvp" multiplicity="(0 -1)" dimension="1"
*/
float mvp[]; // Cached MVP from when shader is built.
/**
* @uml.property name="drag_handles"
* @uml.associationEnd
*/
LDrawDragHandleInstance drag_handles; // List of drag handles - deferred to
// draw at the end for perf and
// correct scaling.
/**
* @uml.property name="scale"
*/
float scale; // Needed to code Allen's res-independent drag
// handles...someday get this from viewport?
public LDrawShaderRenderer() {
dl_now = new LDrawDLBuilder();
color_now = new float[4];
compl_now = new float[4];
color_stack = new float[COLOR_STACK_DEPTH * 4];
tex_stack = new LDrawTextureSpec[TEXTURE_STACK_DEPTH];
transform_stack = new float[TRANSFORM_STACK_DEPTH * 16];
transform_now = new float[16];
cull_now = new float[16];
dl_stack = new LDrawDLBuilder[DL_STACK_DEPTH];
mvp = new float[16];
tex_now = new LDrawTextureSpec();
}
// ========== set_color4fv
// ========================================================
//
// Purpose: Copies an RGBA color, but handles the special ptrs 0L and -1L by
// converting them into the 'magic' colors 0,0,0,0 and 1,1,1,0 that
// the shader wants.
//
// Notes: The shader, when it sees alpha = 0, mixes between the
// attribute-set
// current and compliment by blending with the red channel: red = 0 is
// current, red = 1 is compliment.
//
// ================================================================================
public static void set_color4fv(float c[], float storage[]) {
if (c.length == 1) {
if (c[0] == 0) {
storage[0] = 0;
storage[1] = 0;
storage[2] = 0;
storage[3] = 0;
} else if (c[0] == -1) {
storage[0] = 1;
storage[1] = 1;
storage[2] = 1;
storage[3] = 0;
}
} else {
for (int i = 0; i < 4; i++)
storage[i] = c[i];
}
}// end set_color4fv
// ================================================================================
// @implementation LDrawShaderRenderer
// ================================================================================
// ========== init:
// ===============================================================
//
// Purpose: initialize our renderer, and grab all basic OpenGL state we
// need.
//
// ================================================================================
public static HashMap<GL2, IntBuffer> progList = new HashMap<GL2, IntBuffer>();
public LDrawShaderRenderer initWithScale(GL2 gl2, float initial_scale,
float[] mv_matrix, float[] proj_matrix) {
// Build our shader if it doesn't exist yet. For now, just stash the GL
// object statically.
if (progList.containsKey(gl2) == false) {
IntBuffer prog = IntBuffer.allocate(1);
progList.put(gl2, prog);
}
IntBuffer prog = progList.get(gl2);
if (prog.get(0) == 0) {
// This list of attribute names matches the text of the GLSL
// attribute
// declarations -
// and its order must match the attr_position...array in the .h.
/**
* @uml.property name="attribs" multiplicity="(0 -1)" dimension="1"
*/
String attribs[] = { "position", "normal", "color", "transform_x",
"transform_y", "transform_z", "transform_w",
"color_current", "color_compliment", "texture_mix" };
int programID = LDrawShaderLoader.LDrawLoadShaderFromFile(gl2,
System.getProperty("user.dir")
+ "/Resource/Shader/test.glsl", attribs);
prog.put(0, programID);
int u_tex = gl2.glGetUniformLocation(prog.get(0), "u_tex");
gl2.glUseProgram(prog.get(0));
// This matches up texture unit 0 with the sampler in the shader.
gl2.glUniform1i(u_tex, 0);
} else {
gl2.glUseProgram(prog.get(0));
}
// todo
// super.init();
scale = initial_scale;
ColorLibrary.sharedColorLibrary()
.colorForCode(LDrawColorT.LDrawCurrentColor)
.getColorRGBA(color_now);
gl2.glVertexAttrib1f(AttributeT.attr_texture_mix.getValue(), 0.0f);
ColorLibrary.sharedColorLibrary().complimentColor(color_now, compl_now);
// Set up the basic transform to be identity - our transform is on top
// of the MVP matrix.
// memset(transform_now,0,sizeof(transform_now));
for (int i = 0; i < transform_now.length; i++)
transform_now[i] = 0;
transform_now[0] = transform_now[5] = transform_now[10] = transform_now[15] = 1.0f;
// "Rip" the MVP matrix from OpenGL. (TODO: does LDraw just have this
// info?)
// We use this for culling.
GLMatrixMath.multMatrices(mvp, proj_matrix, mv_matrix);
for (int i = 0; i < mvp.length; i++)
cull_now[i] = mvp[i];
// Create a DL session to match our lifetime.
session = new LDrawDLSession(mv_matrix);
// Set up GL state for attribute drawing, not the fixed function drawing
// we used to do.
gl2.glEnableVertexAttribArray(AttributeT.attr_position.getValue());
gl2.glEnableVertexAttribArray(AttributeT.attr_normal.getValue());
gl2.glEnableVertexAttribArray(AttributeT.attr_color.getValue());
gl2.glDisableClientState(GL2.GL_COLOR_ARRAY);
gl2.glDisableClientState(GL2.GL_NORMAL_ARRAY);
gl2.glDisableClientState(GL2.GL_VERTEX_ARRAY);
drag_handles = null;
return this;
}// end init:
// ========== dealloc:
// ============================================================
//
// Purpose: Clean up our state. Note that this "triggers" the draw from
// our
// display list session that has stored up some of our draw calls.
//
// ================================================================================
public void dealloc(GL2 gl2) {
LDrawDragHandleInstance dh;
// todo
// LDrawDLSessionDrawAndDestroy(session);
// session = nil;
// Go through and draw the drag handles...
// for(dh = drag_handles; dh != null; dh = dh->next)
// {
// float s = dh->size / scale;
// float m[16] = { s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0, dh->xyz[0],
// dh->xyz[1],dh->xyz[2], 1.0 };
//
// [this pushMatrix:m];
// [this drawDragHandleImm:dh->xyz withSize:dh->size];
// [this popMatrix];
// }
// Put back OGL state to what LDraw usually has.
gl2.glUseProgram(0);
int a;
for (a = 0; a < AttributeT.attr_count.getValue(); ++a)
gl2.glDisableVertexAttribArray(a);
gl2.glEnableClientState(GL2.GL_COLOR_ARRAY);
gl2.glEnableClientState(GL2.GL_NORMAL_ARRAY);
gl2.glEnableClientState(GL2.GL_VERTEX_ARRAY);
// LDrawBDPDestroy(pool);
// [super dealloc];
}// end dealloc:
// ========== pushMatrix:
// =========================================================
//
// Purpose: accumulate a transform temporarily. The transform will be
// 'grabbed'
// later if a DL is made.
//
// Notes: our current texture is mapped in _object_ coordinates. So if we
// are
// going to transform our coordinate system AND we have textures active
// we produce a new texture whose planar projection matches our new
// coordinates.
//
// IF we used eye-space texturing this would not be necessary. But
// eye space texturing was actually more complex than this case in the
// shader.
//
// ================================================================================
public void pushMatrix(float matrix[]) {
assert (transform_stack_top < TRANSFORM_STACK_DEPTH);
for (int i = 0; i < transform_now.length; i++)
transform_stack[16 * transform_stack_top + i] = transform_now[i];
float[] temp = new float[16];
for (int i = 0; i < 16; i++)
temp[i] = transform_stack[16 * transform_stack_top + i];
GLMatrixMath.multMatrices(transform_now, temp, matrix);
++transform_stack_top;
pushTexture(tex_now);
if (tex_now.getTex_obj() != 0) {
// If we have a current texture, transform the tetxure by "matrix".
// TODO: doc _why_ this works mathematically.
float s[], t[];
s = new float[4];
t = new float[4];
GLMatrixMath.applyMatrixTranspose(s, matrix, tex_now.plane_s);
GLMatrixMath.applyMatrixTranspose(t, matrix, tex_now.plane_t);
for (int i = 0; i < 4; i++) {
tex_now.plane_s[i] = s[i];
tex_now.plane_t[i] = t[i];
}
// memcpy(tex_now.plane_s,s,sizeof(s));
// memcpy(tex_now.plane_t,t,sizeof(t));
}
GLMatrixMath.multMatrices(cull_now, mvp, transform_now);
}// end pushMatrix:
// ========== checkCull:to:
// =======================================================
//
// Purpose: cull out bounding boxes that are off-screen. We transform to
// clip
// coordinates and see if the AABB (in screen space) of the original
// bounding cube (in MV coordinates) is now entirely out of clip bounds.
//
// Notes: we also look at the screen-space size of the box to decide if
// we can
// cull it because it's tiny or replace it with a box.
//
// TODO: change hard-coded values to be compensated for aspect ratio,
// etc.
//
// ================================================================================
public CullingT checkCull(float[] minXYZ, float[] maxXYZ) {
if (minXYZ[0] > maxXYZ[0] || minXYZ[1] > maxXYZ[1]
|| minXYZ[2] > maxXYZ[2])
return CullingT.cull_skip;
float aabb_model[] = { minXYZ[0], minXYZ[1], minXYZ[2], maxXYZ[0],
maxXYZ[1], maxXYZ[2] };
float aabb_ndc[] = new float[6];
GLMatrixMath.aabbToClipbox(aabb_model, cull_now, aabb_ndc);
if (aabb_ndc[3] < -1.0f || aabb_ndc[4] < -1.0f || aabb_ndc[0] > 1.0f
|| aabb_ndc[1] > 1.0f) {
return CullingT.cull_skip;
}
int x_pix = (int) ((aabb_ndc[3] - aabb_ndc[0]) * 512.0);
int y_pix = (int) ((aabb_ndc[4] - aabb_ndc[1]) * 384.0);
int dim = Math.max(x_pix, y_pix);
if (dim < 1)
return CullingT.cull_skip;
if (dim < 10)
return CullingT.cull_box;
return CullingT.cull_draw;
}// end pushMatrix:to:
//
// ========== drawBoxFrom:to:
// =====================================================
//
// Purpose: draw an axis-aligned cube of a given size.
//
// Notes: this routine retains a single unit-cube display list that can
// be
// drawn multiple times; the DL system will end up instancing it for us.
// Because BrickSmith ensures GL resources are never lost, we can just
// keep the cube statically.
//
// ================================================================================
static LDrawDL unit_cube = null;
public void drawBoxFrom(GL2 gl2, float[] minXyz, float[] maxXyz) {
if (unit_cube == null) {
LDrawDLBuilder builder = new LDrawDLBuilder();
float top[] = { 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0 };
float bot[] = { 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1 };
float lft[] = { 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0 };
float rgt[] = { 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 };
float frt[] = { 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1 };
float bak[] = { 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0 };
float c[] = new float[4];
float n[] = { 0, 1, 0 };
builder.addQuad(top, n, c);
builder.addQuad(bot, n, c);
builder.addQuad(lft, n, c);
builder.addQuad(rgt, n, c);
builder.addQuad(frt, n, c);
builder.addQuad(bak, n, c);
unit_cube = builder.finish(gl2);
}
float dim[] = { maxXyz[0] - minXyz[0], maxXyz[1] - minXyz[1],
maxXyz[2] - minXyz[2] };
float rescale[] = { dim[0], 0, 0, 0, 0, dim[1], 0, 0, 0, 0, dim[2], 0,
minXyz[0], minXyz[1], minXyz[2], 1 };
pushMatrix(rescale);
drawDL(gl2, unit_cube);
popMatrix();
}// end drawBoxFrom:to:
//
//
// ========== popMatrix:
// ==========================================================
//
// Purpose: reset one level of the matrix stack.
//
// ================================================================================
public void popMatrix() {
// We always push a texture frame with every matrix frame for now, so
// that
// we can re-transform the tex projection. We simply have 2x the slots
// in our stacks.
popTexture();
assert (transform_stack_top > 0);
--transform_stack_top;
// memcpy(transform_now, transform_stack + 16 * transform_stack_top,
// sizeof(transform_now));
for (int i = 0; i < 16; i++)
transform_now[i] = transform_stack[16 * transform_stack_top + i];
GLMatrixMath.multMatrices(cull_now, mvp, transform_now);
}// end popMatrix:
// ========== pushColor:
// ==========================================================
//
// Purpose: push a color change onto the stack. This sets the RGBA for
// the
// current and compliment color for DLs that use the current color.
//
// ================================================================================
public void pushColor(float color[]) {
assert (color_stack_top < COLOR_STACK_DEPTH);
color_stack[0 + color_stack_top * 4] = color_now[0];
color_stack[1 + color_stack_top * 4] = color_now[1];
color_stack[2 + color_stack_top * 4] = color_now[2];
color_stack[3 + color_stack_top * 4] = color_now[3];
++color_stack_top;
if (color.length != 0) {
if (color.length == 1)
color = compl_now;
color_now[0] = color[0];
color_now[1] = color[1];
color_now[2] = color[2];
color_now[3] = color[3];
ColorLibrary.sharedColorLibrary().complimentColor(color_now,
compl_now);
}
}// end pushColor:
// ========== popColor:
// ===========================================================
//
// Purpose: pop the stack of current colors that has previously been
// pushed.
//
// ================================================================================
public void popColor() {
assert (color_stack_top > 0);
--color_stack_top;
color_now[0] = color_stack[0 + color_stack_top * 4];
color_now[1] = color_stack[1 + color_stack_top * 4];
color_now[2] = color_stack[2 + color_stack_top * 4];
color_now[3] = color_stack[3 + color_stack_top * 4];
ColorLibrary.sharedColorLibrary().complimentColor(color_now, compl_now);
}// end popColor:
// ========== pushTexture:
// ========================================================
//
// Purpose: change the current texture to a new one, specified by a spec
// with
// textures and projection.
//
// ================================================================================
public void pushTexture(LDrawTextureSpec spec) {
assert (texture_stack_top < TEXTURE_STACK_DEPTH);
try {
tex_stack[texture_stack_top] = (LDrawTextureSpec) tex_now.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// memcpy(tex_stack+texture_stack_top,&tex_now,sizeof(tex_now));
++texture_stack_top;
// memcpy(&tex_now,spec,sizeof(tex_now));
try {
tex_now = (LDrawTextureSpec) spec.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// if (dl_stack_top != 0)
// dl_now.setTex(tex_now);
}// end pushTexture:
// ========== popTexture:
// =========================================================
//
// Purpose: pop a texture off the stack that was previously pushed.
// When
// the
// last texture is popped, we go back to being untextured.
//
// ================================================================================
public void popTexture() {
assert (texture_stack_top > 0);
--texture_stack_top;
try {
tex_now = (LDrawTextureSpec) (tex_stack[texture_stack_top].clone());
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// if (dl_stack_top != 0)
// dl_now.setTex(tex_now);
}// end popTexture:
// ========== pushWireFrame:
// ======================================================
//
// Purpose: push a change to wire frame mode. This is nested - when
// the
// last
// "wire frame" is popped, we are no longer wire frame.
//
// ================================================================================
public void pushWireFrame(GL2 gl2) {
synchronized (gl2) {
if (isWireFrame == false && useWireFrame) {
isWireFrame = true;
gl2.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE);
}
}
}// end pushWireFrame:
// ========== popWireFrame:
// =======================================================
//
// Purpose: undo a previous wire frame command - the push and pops
// must
// be
// balanced.
//
// ================================================================================
public void popWireFrame(GL2 gl2) {
synchronized (gl2) {
if (isWireFrame == true) {
isWireFrame = false;
gl2.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_FILL);
}
}
}// end popWireFrame:
// ========== drawQuad:normal:color:
// ==============================================
//
// Purpose: Adds one quad to the current display list.
//
// Notes: This should only be called after a dlBegin has been called;
// client
// code only gets a protocol interface to this API by calling beginDL
// first.
//
// ================================================================================
public void drawQuad(float[] vertices, float[] normal, float[] color) {
assert (dl_stack_top == 0);
float c[] = new float[4];
set_color4fv(color, c);
dl_now.addQuad(vertices, normal, c);
}// end drawQuad:normal:color:
// ========== drawTri:normal:color:
// ===============================================
//
// Purpose: Adds one triangle to the current display list.
//
// ================================================================================
public void drawTri(float[] vertices, float[] normal, float[] color) {
assert (dl_stack_top == 0);
float c[] = new float[4];
;
set_color4fv(color, c);
dl_now.addTri(vertices, normal, c);
}// end drawTri:normal:color:
// ========== drawLine:normal:color:
// ==============================================
//
// Purpose: Adds one line to the current display list.
//
// ================================================================================
public void drawLine(float[] vertices, float[] normal, float[] color) {
assert (dl_stack_top == 0);
float c[] = new float[4];
set_color4fv(color, c);
dl_now.addLine(vertices, normal, c);
}// end drawLine:normal:color:
// ========== drawDragHandle:withSize:
// ============================================
//
// Purpose: This draws one drag handle using the current transform.
//
// Notes: We don't draw anything - we just grab a list link and stash
// the
// drag handle in "global model space" - that is, the space that the
// root of all drawing happens, without the local part transform.
// We do that so that when we pop out all local transforms and draw
// later we will be in the right place, but we'll have no local
// scaling
// that could deform our handle.
//
// ================================================================================
public void drawDragHandle(float[] xyz, float size) {
LDrawDragHandleInstance dh = new LDrawDragHandleInstance();
dh.setNext(drag_handles);
drag_handles = dh;
dh.setSize(7.0f);
float handle_local[] = { xyz[0], xyz[1], xyz[2], 1.0f };
float handle_world[] = new float[4];
GLMatrixMath.applyMatrix(handle_world, transform_now, handle_local);
float[] xyz_dh = dh.getXyz();
xyz_dh[0] = handle_world[0];
xyz_dh[1] = handle_world[1];
xyz_dh[2] = handle_world[2];
dh.setSize(size);
}// end drawDragHandle:withSize:
// ========== drawDragHandle:withSize:
// ============================================
//
// Purpose: Draw a drag handle - for realzies this time
//
// Notes: This routine builds a one-off sphere VBO as needed.
// BrickSmith
// guarantees that we never lose our shared group of GL contexts, so
// we
// don't have to worry about the last context containing the VBO
// going
// away.
//
// The vertex format for the sphere handle is just pure vertices -
// since
// the draw routine sets up its own VAO with its own internal format,
// there's no need to depend on or conform to vertex formats for the
// rest
// of the drawing system.
//
// ================================================================================
public static IntBuffer vaoTag = IntBuffer.allocate(1);
public static IntBuffer vboTag = IntBuffer.allocate(1);
public static IntBuffer vboVertexCount = IntBuffer.allocate(1);
public void drawDragHandleImm(GL2 gl2, float xyz, float size) {
if (vaoTag.get() == 0) {
// Bail if we've already done it.
int latitudeSections = 8;
int longitudeSections = 8;
float latitudeRadians = (float) (Math.PI / latitudeSections); // lat.
// wraps
// halfway
// around sphere
float longitudeRadians = (float) (2 * Math.PI / longitudeSections); // long.
// wraps
// all
// the way
IntBuffer vertexCount = IntBuffer.allocate(1);
ByteBuffer vertexes;
int latitudeCount = 0;
int longitudeCount = 0;
float latitude = 0;
float longitude = 0;
// ---------- Generate Sphere
// -----------------------------------------------
// Each latitude strip begins with two vertexes at the prime
// meridian,
// then
// has two more vertexes per segment thereafter.
vertexCount.put((2 + longitudeSections * 2) * latitudeSections);
gl2.glGenBuffers(1, vboTag);
gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, vboTag.get());
gl2.glBufferData(GL2.GL_ARRAY_BUFFER, vertexCount.get() * 3, null,
GL2.GL_STATIC_DRAW);
vertexes = gl2.glMapBuffer(GL2.GL_ARRAY_BUFFER, GL2.GL_WRITE_ONLY);
// Calculate vertexes for each strip of latitude.
for (latitudeCount = 0; latitudeCount < latitudeSections; latitudeCount += 1) {
latitude = (latitudeCount * latitudeRadians);
// Include the prime meridian twice; once to start the strip and
// once
// to
// complete the last triangle of the -1 meridian.
for (longitudeCount = 0; longitudeCount <= longitudeSections; longitudeCount += 1) {
longitude = longitudeCount * longitudeRadians;
// Ben says: when we are "pushing" vertices into a
// GL_WRITE_ONLY
// mapped
// buffer, we should really
// never read back from the vertices that we read to - the
// memory we
// are
// writing to often has funky
// properties like being uncached which make it expensive to
// do
// anything
// other than what we said we'd
// do (and we said: we are only going to write to them).
//
// Mind you it's moot in this case since we only need to
// write
// vertices.
// Top vertex
vertexes.put(0,
(byte) (Math.cos(longitude) * Math.sin(latitude)));
vertexes.put(1,
(byte) (Math.sin(longitude) * Math.sin(latitude)));
vertexes.put(2, (byte) (Math.cos(latitude)));
// *vertexes++ =cos(longitude)*sin(latitude);
// *vertexes++ =sin(longitude)*sin(latitude);
// *vertexes++ =cos(latitude);
// Bottom vertex
vertexes.put(
3,
(byte) (Math.cos(longitude) * Math.sin(latitude
+ latitudeRadians)));
vertexes.put(
4,
(byte) (Math.sin(longitude) * Math.sin(latitude
+ latitudeRadians)));
vertexes.put(5,
(byte) (Math.cos(latitude + latitudeRadians)));
// *vertexes++ = cos(longitude)*sin(latitude +
// latitudeRadians);
// *vertexes++ = sin(longitude)*sin(latitude +
// latitudeRadians);
// *vertexes++ = cos(latitude + latitudeRadians);
}
}
gl2.glUnmapBuffer(GL2.GL_ARRAY_BUFFER);
gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
// ---------- Optimize
// ------------------------------------------------------
vboVertexCount = vertexCount;
// Encapsulate in a VAO
gl2.glGenVertexArrays(1, vaoTag);
gl2.glBindVertexArray(vaoTag.get());
gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, vboTag.get());
gl2.glEnableVertexAttribArray(AttributeT.attr_position.getValue());
gl2.glEnableVertexAttribArray(AttributeT.attr_normal.getValue());
// Normal and vertex use the same data - in a unit sphere the
// normals
// are
// the vertices!
gl2.glVertexAttribPointer(AttributeT.attr_position.getValue(), 3,
GL2.GL_FLOAT, false, 3, (Buffer) (IntBuffer.allocate(0)));
gl2.glVertexAttribPointer(AttributeT.attr_normal.getValue(), 3,
GL2.GL_FLOAT, false, 3, (Buffer) (IntBuffer.allocate(0)));
// The sphere color is constant - no need to get it from per-vertex
// data.
gl2.glBindVertexArray(0);
gl2.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
}
gl2.glDisable(GL2.GL_TEXTURE_2D);
int i;
for (i = 0; i < 4; ++i)
gl2.glVertexAttrib4f(AttributeT.attr_transform_x.getValue() + i,
transform_now[i], transform_now[4 + i],
transform_now[8 + i], transform_now[12 + i]);
gl2.glVertexAttrib4f(AttributeT.attr_color.getValue(), 0.50f, 0.53f,
1.00f, 1.00f); // Nice lavendar
// color
// for the whole sphere.
gl2.glBindVertexArray(vaoTag.get());
gl2.glDrawArrays(GL2.GL_TRIANGLE_STRIP, 0, vboVertexCount.get());
gl2.glBindVertexArray(0); // Failing to unbind can cause bizarre
// crashes
// if other VAOs are in display lists
gl2.glEnable(GL2.GL_TEXTURE_2D);
}// end drawDragHandleImm:
// ========== beginDL:
// ============================================================
//
// Purpose: This begins accumulating a display list.
//
// ================================================================================
public ILDrawCollector beginDL() {
assert (dl_stack_top < DL_STACK_DEPTH);
dl_stack[dl_stack_top] = dl_now;
++dl_stack_top;
dl_now = new LDrawDLBuilder();
return this;
}// end beginDL:
// ========== endDL:cleanupFunc:
// ==================================================
//
// Purpose: close off a DL, returning the display list if there is
// one.
//
// ================================================================================
public ILDrawDLHandle endDL(GL2 gl2, LDrawDLCleanup_f func) {
assert (dl_stack_top > 0);
LDrawDL dl = dl_now != null ? dl_now.finish(gl2) : null;
--dl_stack_top;
dl_now = dl_stack[dl_stack_top];
ILDrawDLHandle outHandle = (ILDrawDLHandle) dl;
return outHandle;
}// end endDL:cleanupFunc:
// ========== drawDL:
// =============================================================
//
// Purpose: draw a DL using the current state. We pass this to our DL
// session
// that sorts out how to actually do tihs.
//
// ================================================================================
public void drawDL(GL2 gl2, ILDrawDLHandle dl) {
if (drawTransparent == false && color_now[3] != 1.0)
return;
if (drawTransparent && color_now[3] == 1.0)
return;
synchronized (this) {
dl.draw(gl2, session, tex_now, color_now, compl_now, transform_now,
false);
}
}// end drawDL:
@Deprecated
public LDrawDLBuilder getDLBuilderNow() {
return dl_now;
}
}